package br3akr.DeadlyDinnerParty.Server.Actions;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;

import br3akr.DeadlyDinnerParty.Server.Engine.Session;
import br3akr.DeadlyDinnerParty.Server.Exceptions.DeadlyDinnerPartyException;
import br3akr.DeadlyDinnerParty.Server.World.Area;
import br3akr.DeadlyDinnerParty.Server.World.GameCharacter;
import br3akr.DeadlyDinnerParty.Server.World.Handcuffs;
import br3akr.DeadlyDinnerParty.Server.World.Item;
import br3akr.DeadlyDinnerParty.Server.World.Key;

public class HandcuffAction extends Action {
	boolean actionComplete;
    private ActionResponse actionResponse;
    public static final Set<String> keywords;
	static
	{
		Set<String>tempKeywords = new HashSet<String>();
		tempKeywords.add("Handcuff");
		tempKeywords.add("Hc");
		tempKeywords.add("Unhandcuff");
		tempKeywords.add("Uh");
		keywords = Collections.unmodifiableSet(tempKeywords);
	}
    
    public HandcuffAction() {
        super("Handcuff", false);
    }
    
    public ActionResponse doAction(String action, Session session) throws DeadlyDinnerPartyException {
		if (action == null) {
			throw new DeadlyDinnerPartyException ("No action found.");
		}
		if (session == null) {
			throw new DeadlyDinnerPartyException ("No session found.");
		}
		
    	StringTokenizer tokenizedAction = new StringTokenizer(action);
    	String keyword = tokenizedAction.nextToken();
    	String param1 = null;
    	
    	if (tokenizedAction.hasMoreTokens()) {
    		param1 = tokenizedAction.nextToken();
    	}
    	
		GameCharacter actor = session.getCharacter();
		
		if (actor == null) {
			throw new DeadlyDinnerPartyException ("No character found for your session.");
		}
    	
    	actionResponse = new ActionResponse();
    	actionResponse.setActingCharacter(session.getCharacter());
    	Area location = session.getCharacter().getLocation();
    	
    	Set<GameCharacter> localOnlookers = location.getAreaOnlookers(session.getCharacter(), null);
    	actionResponse.addAffectedArea(location);
    	Handcuffs hc = null;
    	GameCharacter target = null;
    	
		switch (keyword.toLowerCase()) {
			case "handcuff":
			case "hc":
		    	if (param1 == null) {
		    		throw new DeadlyDinnerPartyException("Who do you want to handcuff?");
		    	}
		    	
		    	target = location.getCharacter(param1);
		    	
		    	if (target == null || target.isHiddenFrom(actor)) {
		    		throw new DeadlyDinnerPartyException ("There is no one here by the name of " + param1);
		    	}
				
				if (actor.isRecovering()) {
					throw new DeadlyDinnerPartyException ("You can not handcuff while recovering.");
				}
				
				if (actor.getStatus() == GameCharacter.Status.INCAPACITATED) {
					throw new DeadlyDinnerPartyException ("You can not handcuff while incapacitated.");
				}
				
				for (Item item : actor.getInventory()) {
					if (item instanceof Handcuffs) {
						hc = (Handcuffs)item;
						break;
					}
				}
				
				if (hc == null) {
					throw new DeadlyDinnerPartyException ("You are not carrying any handcuffs.");
				}
				
				if (target.getStatus() != GameCharacter.Status.INCAPACITATED) {
					throw new DeadlyDinnerPartyException ("You can not handcuff a character that is not incapacitated.");
				}
				
				actor.removeItem(hc);
				target.handcuff(hc);
				actionResponse.addOnlookers(localOnlookers, actor.getName() + " slaps handcuffs on " + target.getName() + ".");
				actionResponse.setActingCharacterDescription("You slap handcuffs on " + target.getName() + ".");
				actionResponse.addTargetCharacter(target);
				actionResponse.setTargetCharacterDescription(target, actor.getName() + " slaps handcuffs on you.");
				beginRecovery(session.getCharacter(), 3000);
				
				break;
			case "unhandcuff":
			case "uh":
		    	if (param1 == null) {
		    		throw new DeadlyDinnerPartyException("Who do you want to unhandcuff?");
		    	}
		    	
		    	target = location.getCharacter(param1);
		    	
		    	if (target == null || target.isHiddenFrom(actor)) {
		    		throw new DeadlyDinnerPartyException ("There is no one here by the name of " + param1);
		    	}
		    	
				if (actor.isRecovering()) {
					throw new DeadlyDinnerPartyException ("You can not handcuff while recovering.");
				}
				
				if (actor.getStatus() == GameCharacter.Status.INCAPACITATED) {
					throw new DeadlyDinnerPartyException ("You can not handcuff while incapacitated.");
				}
				
				if (target.getHandcuffs() == null) {
					throw new DeadlyDinnerPartyException ("That character is not wearing handcuffs.");
				}
				
				Key handcuffKey = null;
				boolean success = false;
				
				for (Item item : actor.getInventory()) {
					if (item instanceof Key) {
						handcuffKey = (Key)item;
						if (handcuffKey.keyForHandcuffLock(target.getHandcuffs())) {
							success = true;
							break;
						}
					}
				}
				
				if (actor.getHeldItem() instanceof Key) {
					handcuffKey = (Key)actor.getHeldItem();
					if (handcuffKey.keyForHandcuffLock(target.getHandcuffs())) {
						success = true;
					}
				}
				
				if (!success) {
					throw new DeadlyDinnerPartyException ("You are not carrying the key for that character's handcuffs.");
				}

				actor.addItem(target.removeHandcuffs());
				String hisHerText = (actor.getGender() == GameCharacter.Gender.MALE) ? "his" : "her";
				actionResponse.addOnlookers(localOnlookers, actor.getName() + " removes the handcuffs from " + target.getName() + " and slips them in " + hisHerText + " pocket.");
				actionResponse.setActingCharacterDescription("You remove the handcuffs from " + target.getName() + " and slip them in your pocket.");
				actionResponse.addTargetCharacter(target);
				actionResponse.setTargetCharacterDescription(target, actor.getName() + " removes your handcuffs, and slips them in " + hisHerText + " pocket.");
				beginRecovery(session.getCharacter(), 3000);
				
				break;
			default:
				break;
		}
        
    	actionComplete = true;
        return actionResponse;
    }
	
    public ActionResponse getActionResponse() {
		return actionResponse;
	}
    
    public Set<String> getKeywords() {
        return keywords;
    }
}